/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cn.edu.thu.thss.hxd.mazedisplay;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.ResourceBundle;
import java.util.Scanner;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import javafx.animation.Animation;
import javafx.animation.FillTransition;
import javafx.animation.FillTransitionBuilder;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.SequentialTransition;
import javafx.animation.SequentialTransitionBuilder;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.DepthTest;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;
import javafx.util.Duration;

/**
 *
 * @author hxd
 */
public class MainPlatformController implements Initializable {
	private static final Random RANDOM = new Random();
	private static final Interpolator INTERPOLATOR = Interpolator.SPLINE(0.295,0.800,0.305,1.000);
	private Group roadGroup;//道路
	
	public  static final int number=18;//道路的格子数
	public static int[][] maze=new int[number][number];//迷宫矩阵
	public Box[][] mazeBoxs=new Box[number][number];//迷宫格子
	public static int time=3;//生成迷宫的动画时长
	public int startRow;//迷宫起点坐标x
	public int startCol;//迷宫起点坐标y
	public int endx;//迷宫终点坐标x
	public int endy;//迷宫终点坐标y
	double gap=2;//砖块之间间隙
	int width=30;//砖块宽
	int height=10;//砖块高
	double tanx=1;//砖块top面错切的角度的tan值
	@FXML
	private Pane mazePane;   
	@FXML
	private SplitPane splitPane;  
	@FXML
	private Button resetBt; 
	@FXML
	private Button loadMazeBt; 
	@FXML
	private Button loadControlBt; 
	@FXML
	private Button runControlBt; 
	@FXML
	private Button quitBt; 
	/**
	 * 
	 */
	List<Animation> animations=new ArrayList<Animation>(); //脚本动画
/**
 * 载入迷宫
 * @param event
 */
	private void loadMaze(ActionEvent event) {
		try {
			loadMap();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
/**
 * 载入脚本
 * @param event
 */
	private void loadControlScript() {
		System.out.println("You clicked me!");
		DocumentBuilderFactory domfac=DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder dombuilder=domfac.newDocumentBuilder();
			 InputStream is=new FileInputStream("examplediagram.xml");
			 Document doc=dombuilder.parse(is);
			 Element root=doc.getDocumentElement();
			 
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		move(0);
		move(0);
		move(0);
		move(0);
		move(3);
		move(0);
		move(4);
		move(1);
		sequentialTransition = SequentialTransitionBuilder.create()
				.node(ball)
				.children(animations)
				//  .cycleCount(Timeline.INDEFINITE)
				.build();
		
		//        label.setText("Hello World!");
	}
	/**
	 * 运行脚本
	 * @param event
	 */
	private void runControlScript(ActionEvent event) {
		sequentialTransition.play();
	}
	/**
	 * 停止脚本
	 * @param event
	 */
	private void stopRun() {
		sequentialTransition.stop();
	}
	/**
	 * 退出程序
	 * @param event
	 */
	private void quit(ActionEvent event) {
		Platform.exit();
	}
	private void help(ActionEvent event) {
		System.out.println("You clicked me!");
		//        label.setText("Hello World!");
	}
	private void about(ActionEvent event) {
		System.out.println("You clicked me!");
		//        label.setText("Hello World!");
	}
	/**
	 * 初始化，铺路。
	 */
	@Override
	public void initialize(URL url, ResourceBundle rb) {
		// TODO
//		System.err.println(mazePane.styleProperty());
//		System.out.println(url+"|"+rb);
		Group totalGroup=createRoads();//铺路
		mazePane.getChildren().add(totalGroup);
		//loadMazeBt
		loadMazeBt.setOnAction(new EventHandler<ActionEvent>() {
			@Override public void handle(ActionEvent t) {
				loadMaze(t);
			}
		}
				);
		resetBt.setOnAction(new EventHandler<ActionEvent>() {
			@Override public void handle(ActionEvent t) {
				resetMap();
			}
		}
				);
		loadControlBt.setOnAction(new EventHandler<ActionEvent>() {
			@Override public void handle(ActionEvent t) {
				loadControlScript();
			}
		}
				);
		runControlBt.setOnAction(new EventHandler<ActionEvent>() {
			@Override public void handle(ActionEvent t) {
				runControlScript(t);
			}
		}
				);
		quitBt.setOnAction(new EventHandler<ActionEvent>() {
			@Override public void handle(ActionEvent t) {
				quit(t);
			}
		}
				);
	}  
	/**
	 * 铺满路
	 * @return
	 */
	public Group createRoads(){
		roadGroup = new Group();
		Color color=Color.web("#079E48",0.7);
		Color edge=Color.web("#080808",0.9);
		int shade=1;
		double x=0;
		double y=10+width;//使得砖块不顶着最上面
		x+=number*(width+gap);
		for(int j=0;j<number;j++){
			for(int i=0;i<number;i++){
				Box box=new Box(width,height,tanx,color,edge,shade);
				box.setLayoutX(x);
				box.setLayoutY(y);
				roadGroup.getChildren().add(box);
				x+=width+gap;
				mazeBoxs[j][i]=box;
				box.type=1;
			}
			x=(number-1-j)*(width+gap);
			y+=width+gap;
		}
		return roadGroup;
	}
	/**
	 * 载入迷宫
	 * @throws Exception
	 */
	public void loadMap() throws Exception{
		File file=new File("maze.bin");
		System.out.println(file.exists());
		boolean hasEnter=false;
		boolean hasExit=true;
		try {
			Scanner scanner=new Scanner(file);
			for(int i=0;i<number;i++){
				for (int j=0;j<number;j++){
					if(scanner.hasNext()){
						mazeBoxs[i][j].type=(scanner.nextInt());
						if(mazeBoxs[i][j].type==0){
							removeBoxAnimation(mazeBoxs[i][j]);
						}else if(mazeBoxs[i][j].type==2){
							hasEnter=true;
							changeTopColor(mazeBoxs[i][j], Color.web("#DC143C"));
							startRow=i;
							startCol=j;
							System.out.println(startRow+"|"+startCol);
							System.out.println(mazeBoxs[i][j].getLayoutX()+"|"+mazeBoxs[i][j].getLayoutY());
						}else if(mazeBoxs[i][j].type==3){
							hasExit=true;
							changeTopColor(mazeBoxs[i][j], Color.web("#ADFF2F"));
							endx=i;
							endy=j;
						}
					}else{
						throw new Exception("wrong data");
					}
				}
			}
			scanner.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return ;
		}
		if(!hasEnter){
			throw new Exception("no Enter");
		}
		if(!hasExit){
			throw new Exception("no Exit");
		}
		addBouncyBall(mazePane);
	}
	/**
	 * 擦除迷宫，铺满路
	 */
	private void resetMap(){
		for(int i=0;i<mazeBoxs.length;i++){
			for(int j=0;j<mazeBoxs[i].length;j++){
				if(mazeBoxs[i][j].type==0){
					addBoxAnimation(mazeBoxs[i][j]);
					mazeBoxs[i][j].type=1;
				}else if(mazeBoxs[i][j].type>1){
					changeTopColor(mazeBoxs[i][j], Color.web("#079E48",0.7).deriveColor(0.0, 1.0, (1 - 0.5*1), 1.0));
					mazeBoxs[i][j].type=1;
				}
			}
		}
	}
	/**
	 * 改变box的top面的颜色
	 * @param box
	 * @param color
	 */
	private void changeTopColor(Box box,Color color){

		FillTransition fillTransiton= FillTransitionBuilder.create()
				.duration(Duration.seconds(time))
				.shape(box.getTop())
				.toValue(color)
				.autoReverse(true)
				.build();
		fillTransiton.play();
	}
	
	/**
	 * 添加铺路动画
	 * @param box
	 */
	private void addBoxAnimation(final Box box){
		final Timeline timeline = new Timeline();
		timeline.getKeyFrames().add(
				new KeyFrame(Duration.seconds(time), new EventHandler<ActionEvent>() {
					@Override public void handle(ActionEvent event) {
						// we are done remove us from scene
						//roadGroup.getChildren().add(box);
						//box.setVisible(true);
					}
				},
				//new KeyValue(box.translateXProperty(), getRandom(0.0f, mazePane.getWidth() - box.getBoundsInLocal().getWidth()),INTERPOLATOR),
				new KeyValue(box.translateYProperty(), 0f),
				new KeyValue(box.opacityProperty(), 1f)
						));
		timeline.play();
	}
	/**
	 * 添加去除砖的动画
	 * @param box
	 */
	private void removeBoxAnimation(final Box box){
//		final Timeline timeline = new Timeline();
//		timeline.getKeyFrames().add(
//				new KeyFrame(Duration.seconds(time),
//						new EventHandler<ActionEvent>() {
//					@Override public void handle(ActionEvent event) {
//						// we are done remove us from scene
//						//roadGroup.getChildren().remove(box);
//					}
//				},
//				//new KeyValue(box.translateXProperty(), getRandom(0.0f, mazePane.getWidth() - box.getBoundsInLocal().getWidth()),INTERPOLATOR),
//				//new KeyValue(box.translateXProperty(), 0f),
//				new KeyValue(box.translateYProperty(),getRandom(50.0f, mazePane.getHeight() - box.getBoundsInLocal().getHeight()),INTERPOLATOR ),
//				new KeyValue(box.opacityProperty(), 0f)
//						));
//		timeline.play();
		removeNodeAnimation(box);
	}
	/**
	 * 添加去除物体的动画
	 * @param box
	 */
	private void removeNodeAnimation(final Node node){
		final Timeline timeline = new Timeline();
		double max=mazePane.getHeight() - node.getBoundsInLocal().getHeight();
		timeline.getKeyFrames().add(
				new KeyFrame(Duration.seconds(time),
						new EventHandler<ActionEvent>() {
					@Override public void handle(ActionEvent event) {
						// we are done remove us from scene
						//roadGroup.getChildren().remove(box);
					}
				},
				//new KeyValue(box.translateXProperty(), getRandom(0.0f, mazePane.getWidth() - box.getBoundsInLocal().getWidth()),INTERPOLATOR),
				//new KeyValue(box.translateXProperty(), 0f),
				
				new KeyValue(node.translateYProperty(),getRandom(50.0f,max ),INTERPOLATOR ),
				new KeyValue(node.opacityProperty(), 0f)
						));
		timeline.play();
	}
	/**
	 *添加一个球
	 * @param scene
	 */
	private Circle ball=new Circle(15);
	private SequentialTransition sequentialTransition;
	private void addBouncyBall( Pane pane){

//		double x=(width+gap)*startCol+width*3;
//		double y=(width+gap)*startRow+10;//使得不顶着最上面
//		System.out.println(x+"="+getBallX(startRow,startCol));
//		System.out.println(y+"="+getBallY(startRow,startCol));
		ball.setCenterX(getBallX(startRow,startCol));
		ball.setCenterY(getBallY(startRow,startCol));
//		System.out.println(x+"|"+y);
		//create simple radial gradient
		RadialGradient gradient1 = new RadialGradient(0, 0, 0.5, 0.5, 1, true, CycleMethod.NO_CYCLE, new Stop[] {
				new Stop(0, Color.WHITE),
				new Stop(1, Color.GREEN)
		});
		ball.setFill(gradient1);
		pane.getChildren().add(ball);
		
		ball.setDepthTest(DepthTest.ENABLE);
	}
	/**
	 * 移动脚本
	 * @param direction  0 up,1 down,2 left ,3 right.
	 */
	public void move(int direction){
		TranslateTransition translateTransition =new TranslateTransition();
		translateTransition.setDuration(Duration.seconds(2));
//		double startx=ball.getLayoutX();
//		double starty=ball.getLayoutY();
//		translateTransition.setFromX(startx);
//		translateTransition.setFromY(starty);
		switch (direction) {
		case 0://up
			translateTransition.setByX(width+gap);
			translateTransition.setByY(-width-gap);
			break;
		case 1://down
			translateTransition.setByX(-width-gap);
			translateTransition.setByY(width+gap);
			break;
		case 2://left
			translateTransition.setByX(-width-gap);
			break;
		case 3://right
			translateTransition.setByX(width+gap);
			break;
		default:
			break;
		}
		translateTransition.setOnFinished(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent event) {
				//
//				System.out.println("now:"+ball.getTranslateX());
				double x=ball.getCenterX()+ball.getTranslateX();
				double y=ball.getCenterY()+ball.getTranslateY();
				int row=getBallRow(x, y);
				int col=getBallCol(x, y);
				System.out.println("now the ball is at [row:"+row+",col"+col+"]");
				if(mazeBoxs[row][col].type==0){//died!
					animations.clear();
					stopRun();
					//add drop animation.
					removeNodeAnimation(ball);
				}else if(mazeBoxs[row][col].type==3){//win!
					animations.clear();
					stopRun();
					//TODO add win animation.
					
				}
			}
		});
		this.animations.add(translateTransition);
	}

	private static float getRandom(double min, double max) {
		return (float)(RANDOM.nextFloat() * (max - min) + min);
	}
	/**
	 * 返回对应的行
	 * @return
	 */
	private int  getBallRow(double x, double y){
		return (int)((y-10)/(width+gap));
	}
	/**
	 * 返回对应的列
	 * @return
	 */
	private int getBallCol(double x,double y){
		return (int)((x+y-10)/(width+gap)-number-1);
	}
//	/**
//	 * 返回对应的x坐标
//	 * @param col 列号
//	 * @return
//	 */
//	private double getBoxX(int row,int col){
//		return (number-row-1)*width+col*(width+gap);
//	}
//	/**
//	 * 返回对应的y坐标
//	 * @param row 行号
//	 * @return
//	 */
//	private double getBoxY(int row,int col){
//		return 10+row*(width*gap);
//		//return 0;
//	}
	private double getBallX(int row,int col){
		return (width+gap)*(col+number-row+1);
		//return (number-row-1)*width+col*(width+gap);
	}
	/**
	 * 得到球的y坐标
	 * @param row
	 * @param col
	 * @return
	 */
	private double getBallY(int row,int col){
		return (width+gap)*row+10;//10为使得不顶着最上面时设置的值
	}
	
	
}
